{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X_train= (105, 4)\n",
      "X_test= (45, 4)\n",
      "y_train= (105, 1)\n",
      "y_test= (45, 1)\n"
     ]
    }
   ],
   "source": [
    "# 导入相关模块\n",
    "import numpy as np\n",
    "from collections import Counter\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn import datasets\n",
    "from sklearn.utils import shuffle\n",
    "# 导入sklearn iris数据集\n",
    "iris = datasets.load_iris()\n",
    "# 打乱数据后的数据与标签\n",
    "X, y = shuffle(iris.data, iris.target, random_state=13)\n",
    "# 数据转换为float32格式\n",
    "X = X.astype(np.float32)\n",
    "# 训练集与测试集的简单划分，训练-测试比例为7：3\n",
    "offset = int(X.shape[0] * 0.7)\n",
    "X_train, y_train = X[:offset], y[:offset]\n",
    "X_test, y_test = X[offset:], y[offset:]\n",
    "# 将标签转换为竖向量\n",
    "y_train = y_train.reshape((-1,1))\n",
    "y_test = y_test.reshape((-1,1))\n",
    "# 打印训练集和测试集大小\n",
    "print('X_train=', X_train.shape)\n",
    "print('X_test=', X_test.shape)\n",
    "print('y_train=', y_train.shape)\n",
    "print('y_test=', y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 定义欧氏距离\n",
    "def compute_distances(X, X_train):\n",
    "    '''\n",
    "    输入：\n",
    "    X：测试样本实例矩阵\n",
    "    X_train：训练样本实例矩阵\n",
    "    输出：\n",
    "    dists：欧式距离\n",
    "    '''\n",
    "    # 测试实例样本量\n",
    "    num_test = X.shape[0]\n",
    "    # 训练实例样本量\n",
    "    num_train = X_train.shape[0]\n",
    "    # 基于训练和测试维度的欧氏距离初始化\n",
    "    dists = np.zeros((num_test, num_train)) \n",
    "    # 测试样本与训练样本的矩阵点乘\n",
    "    M = np.dot(X, X_train.T)\n",
    "    # 测试样本矩阵平方\n",
    "    te = np.square(X).sum(axis=1)\n",
    "    # 训练样本矩阵平方\n",
    "    tr = np.square(X_train).sum(axis=1)\n",
    "    # 计算欧式距离\n",
    "    dists = np.sqrt(-2 * M + tr + np.matrix(te).T)    \n",
    "    return dists"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "dists = compute_distances(X_test, X_train)\n",
    "plt.imshow(dists, interpolation='none')\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 定义预测函数\n",
    "def predict_labels(y_train, dists, k=1):\n",
    "    '''\n",
    "    输入：\n",
    "    y_train：训练集标签\n",
    "    dists：测试集与训练集之间的欧氏距离矩阵\n",
    "    k：k值\n",
    "    输出：\n",
    "    y_pred：测试集预测结果\n",
    "    '''\n",
    "    # 测试样本量\n",
    "    num_test = dists.shape[0]\n",
    "    # 初始化测试集预测结果\n",
    "    y_pred = np.zeros(num_test) \n",
    "    # 遍历   \n",
    "    for i in range(num_test):\n",
    "        # 初始化最近邻列表\n",
    "        closest_y = []\n",
    "        # 按欧氏距离矩阵排序后取索引，并用训练集标签按排序后的索引取值\n",
    "    # 最后拉平列表\n",
    "    # 注意np.argsort函数的用法\n",
    "        labels = y_train[np.argsort(dists[i, :])].flatten()\n",
    "        # 取最近的k个值\n",
    "        closest_y = labels[0:k]\n",
    "        # 对最近的k个值进行计数统计\n",
    "        # 这里注意collections模块中的计数器Counter的用法\n",
    "        c = Counter(closest_y)\n",
    "        # 取计数最多的那一个类别\n",
    "        y_pred[i] = c.most_common(1)[0][0]    \n",
    "    return y_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Got 44/45 correct=>accuracy:0.977778\n"
     ]
    }
   ],
   "source": [
    "# 测试集预测结果\n",
    "y_test_pred = predict_labels(y_train, dists, k=1)\n",
    "y_test_pred = y_test_pred.reshape((-1, 1))\n",
    "# 找出预测正确的实例\n",
    "num_correct = np.sum(y_test_pred == y_test)\n",
    "# 计算准确率\n",
    "accuracy = float(num_correct) / X_test.shape[0]\n",
    "print('Got %d/%d correct=>accuracy:%f'% (num_correct, X_test.shape[0], accuracy))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "k = 1, accuracy = 0.904762\n",
      "k = 1, accuracy = 1.000000\n",
      "k = 1, accuracy = 0.952381\n",
      "k = 1, accuracy = 0.857143\n",
      "k = 1, accuracy = 0.952381\n",
      "k = 3, accuracy = 0.857143\n",
      "k = 3, accuracy = 1.000000\n",
      "k = 3, accuracy = 0.952381\n",
      "k = 3, accuracy = 0.857143\n",
      "k = 3, accuracy = 0.952381\n",
      "k = 5, accuracy = 0.857143\n",
      "k = 5, accuracy = 1.000000\n",
      "k = 5, accuracy = 0.952381\n",
      "k = 5, accuracy = 0.904762\n",
      "k = 5, accuracy = 0.952381\n",
      "k = 8, accuracy = 0.904762\n",
      "k = 8, accuracy = 1.000000\n",
      "k = 8, accuracy = 0.952381\n",
      "k = 8, accuracy = 0.904762\n",
      "k = 8, accuracy = 0.952381\n",
      "k = 10, accuracy = 0.952381\n",
      "k = 10, accuracy = 1.000000\n",
      "k = 10, accuracy = 0.952381\n",
      "k = 10, accuracy = 0.904762\n",
      "k = 10, accuracy = 0.952381\n",
      "k = 12, accuracy = 0.952381\n",
      "k = 12, accuracy = 1.000000\n",
      "k = 12, accuracy = 0.952381\n",
      "k = 12, accuracy = 0.857143\n",
      "k = 12, accuracy = 0.952381\n",
      "k = 15, accuracy = 0.952381\n",
      "k = 15, accuracy = 1.000000\n",
      "k = 15, accuracy = 0.952381\n",
      "k = 15, accuracy = 0.857143\n",
      "k = 15, accuracy = 0.952381\n",
      "k = 20, accuracy = 0.952381\n",
      "k = 20, accuracy = 1.000000\n",
      "k = 20, accuracy = 0.952381\n",
      "k = 20, accuracy = 0.761905\n",
      "k = 20, accuracy = 0.952381\n",
      "k = 50, accuracy = 1.000000\n",
      "k = 50, accuracy = 1.000000\n",
      "k = 50, accuracy = 0.904762\n",
      "k = 50, accuracy = 0.761905\n",
      "k = 50, accuracy = 0.904762\n",
      "k = 100, accuracy = 0.285714\n",
      "k = 100, accuracy = 0.380952\n",
      "k = 100, accuracy = 0.333333\n",
      "k = 100, accuracy = 0.238095\n",
      "k = 100, accuracy = 0.190476\n"
     ]
    }
   ],
   "source": [
    "### 5折交叉验证\n",
    "num_folds = 5\n",
    "# 候选k值\n",
    "k_choices = [1, 3, 5, 8, 10, 12, 15, 20, 50, 100]\n",
    "X_train_folds = []\n",
    "y_train_folds = []\n",
    "# 训练数据划分\n",
    "X_train_folds = np.array_split(X_train, num_folds)\n",
    "# 训练标签划分\n",
    "y_train_folds = np.array_split(y_train, num_folds)\n",
    "k_to_accuracies = {}\n",
    "# 遍历所有候选k值\n",
    "for k in k_choices:\n",
    "    # 五折遍历    \n",
    "    for fold in range(num_folds): \n",
    "        # 对传入的训练集单独划出一个验证集作为测试集\n",
    "        validation_X_test = X_train_folds[fold]\n",
    "        validation_y_test = y_train_folds[fold]\n",
    "        temp_X_train = np.concatenate(X_train_folds[:fold] + X_train_folds[fold + 1:])\n",
    "        temp_y_train = np.concatenate(y_train_folds[:fold] + y_train_folds[fold + 1:])       \n",
    "        # 计算距离\n",
    "        temp_dists = compute_distances(validation_X_test, temp_X_train)\n",
    "        temp_y_test_pred = predict_labels(temp_y_train, temp_dists, k=k)\n",
    "        temp_y_test_pred = temp_y_test_pred.reshape((-1, 1))       \n",
    "        # 查看分类准确率\n",
    "        num_correct = np.sum(temp_y_test_pred == validation_y_test)\n",
    "        num_test = validation_X_test.shape[0]\n",
    "        accuracy = float(num_correct) / num_test\n",
    "        k_to_accuracies[k] = k_to_accuracies.get(k,[]) + [accuracy]\n",
    "\n",
    "\n",
    "# 打印不同 k 值不同折数下的分类准确率\n",
    "for k in sorted(k_to_accuracies):    \n",
    "      for accuracy in k_to_accuracies[k]:\n",
    "        print('k = %d, accuracy = %f' % (k, accuracy))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 打印不同 k 值不同折数下的分类准确率\n",
    "for k in k_choices:\n",
    "    # 取出第k个k值的分类准确率\n",
    "    accuracies = k_to_accuracies[k]\n",
    "    # 绘制不同k值准确率的散点图\n",
    "    plt.scatter([k] * len(accuracies), accuracies)\n",
    "# 计算准确率均值并排序\n",
    "accuracies_mean = np.array([np.mean(v) for k,v in sorted(k_to_accuracies.items())])\n",
    "# 计算准确率标准差并排序\n",
    "accuracies_std = np.array([np.std(v) for k,v in sorted(k_to_accuracies.items())])\n",
    "# 绘制有置信区间的误差棒图\n",
    "plt.errorbar(k_choices, accuracies_mean, yerr=accuracies_std)\n",
    "# 绘图标题\n",
    "plt.title('Cross-validation on k')\n",
    "# x轴标签\n",
    "plt.xlabel('k')\n",
    "# y轴标签\n",
    "plt.ylabel('Cross-validation accuracy')\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Got 44 / 45 correct => accuracy: 0.977778\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Installation\\anaconda\\install\\lib\\site-packages\\ipykernel_launcher.py:6: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n",
      "  \n"
     ]
    }
   ],
   "source": [
    "# 导入KneighborsClassifier模块\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "# 创建k近邻实例\n",
    "neigh = KNeighborsClassifier(n_neighbors=10)\n",
    "# k近邻模型拟合\n",
    "neigh.fit(X_train, y_train)\n",
    "# k近邻模型预测\n",
    "y_pred = neigh.predict(X_test)\n",
    "# 预测结果数组重塑\n",
    "y_pred = y_pred.reshape((-1, 1))\n",
    "# 统计预测正确的个数\n",
    "num_correct = np.sum(y_pred == y_test)\n",
    "# 计算准确率\n",
    "accuracy = float(num_correct) / X_test.shape[0]\n",
    "print('Got %d / %d correct => accuracy: %f' % (num_correct, X_test.shape[0], accuracy))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
